﻿
//Copyright 1997-2009 Syrinx Development, Inc.
//This file is part of the Syrinx Web Application Framework (SWAF).
// == BEGIN LICENSE ==
//
// Licensed under the terms of any of the following licenses at your
// choice:
//
//  - GNU General Public License Version 3 or later (the "GPL")
//    http://www.gnu.org/licenses/gpl.html
//
//  - GNU Lesser General Public License Version 3 or later (the "LGPL")
//    http://www.gnu.org/licenses/lgpl.html
//
//  - Mozilla Public License Version 1.1 or later (the "MPL")
//    http://www.mozilla.org/MPL/MPL-1.1.html
//
// == END LICENSE ==
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Xml;

using Swaf.BizObj;
using Swaf.BizRule;
using Swaf.Container;
using Swaf.Gui;
using Swaf.Security;

[assembly: WebResource("ScsAspNet.GoogleMap.Gui.AspNet.script.GoogleMap.js", "application/x-javascript")]
namespace GoogleMap.Gui.AspNet
{
	[ParseChildren(true, "PushPins")]
	public class GoogleMapBizObjListDisplay : Swaf.Gui.AspNet2.UserControl, IBizObjListDisplay2, IMapDisplay
	{
		public enum PanZoomType { none, zoomOnly, smallPanZoom, panZoom, largePanZoom }

		protected IBizObj m_bizObj = null;
		protected IBizObjCursor m_bizObjCursor = null;
		protected bool m_writenMapIconSetupScript = false;

		public GoogleMapBizObjListDisplay()
			: base()
		{
			base.m_baseCtlType = BizProcWidgetType.list;
		}
		public GoogleMapBizObjListDisplay(ActiveWidget widget)
			: base(widget)
		{
			base.m_baseCtlType = BizProcWidgetType.list;
		}


		protected static string s_initOnLoad = "$(document).ready(initializeGoogleMaps);$(window).unload(function(){GUnload();});";
		//protected static string s_initOnLoad = "var mapInit = new Array();$(document).ready($getScript(\"{0}\",initializeGoogleMaps));$(window).unload(function(){GUnload();});";
		protected override void OnLoad(EventArgs e)
		{
			base.OnLoad(e);

			if (!(BPC.ActiveWidgets.ContainsKey(WidgetId)))
				BPC.defineActiveWidget(new ActiveWidget(this, BPC, State));

			if (State.State.get("m_pinHandlers") == null)
				State.State.put("m_pinHandlers", m_pinHandlers);

			Swaf.IApplication app = Swaf.Application.currentApp;
			string mapKey = "";
			object cid = app.securityMgr.currentPrincipal.additionalInfo.get("companyId");
			IBizObj company = app.ruleMgr.execute("getCachedCompanyInfo", cid).CallResults as IBizObj;
			if (company != null && company.containsField("settings.googleMapKey") && company.get("settings.googleMapKey").ToString().Length > 0)
				mapKey = company.get("settings.googleMapKey").ToString();

			string scriptUrl = "http://maps.google.com/maps?file=api&v=2&key={0}&sensor=false".Replace("{0}", mapKey); ;
			Page.ClientScript.RegisterClientScriptInclude("SyrinxGoogleMapg1", scriptUrl);
//            string scriptUrl = @"	<script type=""text/javascript"" src=""http://www.google.com/jsapi?key=ABQIAAAA-ByhZxU9vTeEy6zbCreE1RQo0j6YqQNz_Gg3VYBYZ5fZ7NrGFRSXV6sh7PJEUgdOHJZwKHQIib5FMQ""></script></head>
//	<script type=""text/javascript"">	google.load(""maps"", ""2"");</script>
//	<script type=""text/javascript"" src=""http://www.google.com/jsapi?key=ABCDEFG""></script>";

//            Page.ClientScript.RegisterClientScriptBlock(typeof(GoogleMapBizObjListDisplay), "SyrinxGoogleMap", scriptUrl);			


			scriptUrl = Page.ClientScript.GetWebResourceUrl(typeof(GoogleMapBizObjListDisplay), "ScsAspNet.GoogleMap.Gui.AspNet.script.GoogleMap.js");
			Page.ClientScript.RegisterClientScriptInclude("SyrinxGoogleMap", scriptUrl);
			Page.ClientScript.RegisterStartupScript(typeof(GoogleMapBizObjListDisplay), "SyrinxGoogleMapinit", s_initOnLoad, true);
			//Page.ClientScript.RegisterStartupScript(typeof(GoogleMapBizObjListDisplay), "SyrinxGoogleMapinit", s_initOnLoad.Replace("{0}", scriptUrl), true);			
		}

		protected virtual void setupMapPointStartupScript()
		{
			if (m_bizObjCursor != null)
			{
				StringBuilder buff = new StringBuilder(1024);
				buff.Append("function ").Append(ClientID).Append("mapSetup(me){");
				getMapPointsScript(buff);
				buff.Append("}");
				Page.ClientScript.RegisterStartupScript(typeof(GoogleMapBizObjListDisplay), ClientID + "Mapinit", buff.ToString(), true);
			}
		}

		protected PanZoomType m_panZoom = PanZoomType.none;
		public PanZoomType PanZoom { get { return (PanZoomType)getOffline("m_panZoom"); } set { putOffline("m_panZoom", value); } }

		protected bool m_showMapTypes = false;
		public bool ShowMapTypes { get { return (bool)getOffline("m_showMapTypes"); } set { putOffline("m_showMapTypes", value); } }

		protected bool m_showMarkerNav = false;
		public bool ShowMarkerNav { get { return (bool)getOffline("m_showMarkerNav"); } set { putOffline("m_showMarkerNav", value); } }

		protected string m_centerLocation = "Cebu City";
		public string CenterAt { get { return (string)getOffline("m_centerLocation"); } set { putOffline("m_centerLocation", value); } }

		protected int m_initialZoom = 5;
		public int InitialZoom { get { return (int)getOffline("m_initialZoom"); } set { putOffline("m_initialZoom", value); } }

		protected string m_prevMarkHtml = "Move to Previous Map Marker";
		public string PrevMarkHtml { get { return (string)getOffline("m_prevMarkHtml"); } set { putOffline("m_prevMarkHtml", value); } }

		protected string m_nextMarkHtml = "Move to Next Map Marker";
		public string NextMarkHtml { get { return (string)getOffline("m_nextMarkHtml"); } set { putOffline("m_nextMarkHtml", value); } }

		protected List<PushPin> m_pinHandlers = new List<PushPin>();
		public List<PushPin> PushPins { get { return (List<PushPin>)getOffline("m_pinHandlers"); } set { putOffline("m_pinHandlers", value); } }

		public void setupMapIcons(IBizObjList[] ico)
		{
			Page.ClientScript.RegisterStartupScript(typeof(GoogleMapBizObjListDisplay), "SyrinxMapPininit", createMapIconsScript(ico).ToString(), true);
		}

		//This is used in the map templates ascx.  This allows the map to be adorned with other html beyond what is generated here.
		public string getMapHtml()
		{
			StringBuilder buff = new StringBuilder(1024);
			if (ShowMarkerNav)
				buff.Append("<button type='button' onclick='moveToMapMarker($(\"#").Append(ClientID).Append("map\"),false)'>")
					.Append(PrevMarkHtml).Append("</button>")
					.Append("<button type='button' onclick='moveToMapMarker($(\"#").Append(ClientID).Append("map\"),true)'>")
					.Append(NextMarkHtml).Append("</button>");

			buff.Append("<div id='").Append(ClientID).Append("map' class='GMapArea ");
			if (PanZoom != PanZoomType.none)
				buff.Append("FullPanZoom ");
			if (ShowMapTypes)
				buff.Append("FullMapping ");
			if (!Swaf.Cmn.IsEmpty(CenterAt))
				buff.Append("{location: \"").Append(CenterAt).Append("\"").Append(", zoom: ").Append(InitialZoom).Append("}");
			buff.Append("' style='width:").Append(Width).Append(";height:").Append(Height).Append(";'></div>");

			return buff.ToString();
		}

		protected virtual bool shouldPositionOnFirst()
		{
			return !Page.IsPostBack;
		}

		public string getMapPointsScript(StringBuilder buff)
		{
			if(buff==null)
				buff = new StringBuilder(1024);
			buff.Append("var gmap = me.data('gmap');");
			buff.Append("gmap.clearOverlays();me.data('markers', null);");
			bool setupFirst = !shouldPositionOnFirst();
			foreach(IBizObj mapPoint in m_bizObjCursor.Source)
			{
				IBizObj addr = mapPoint.get("location") as IBizObj;
				IBizObj parent = mapPoint.get("parent") as IBizObj;
				if (!setupFirst)
				{
					setupFirst = true;
					string lat = (string)addr.get("latitude");
					string lng = (string)addr.get("longitude");
					string loc = (string)addr.get("location");
					if (!Swaf.Cmn.IsEmpty(lat) && !Swaf.Cmn.IsEmpty(lng))
						buff.Append("gmap.setCenter(new google.maps.LatLng(").Append(lat).Append(",").Append(lng).Append("));");
					else if (loc != null)
						buff.Append("setGMapCenterOnLocation(me,'").Append(loc.Replace("'", "\\")).Append("');");
				}
				createMarkerScript(buff, mapPoint);
			}

			return buff.ToString();
		}

		static Regex s_nonWord = new Regex(@"\W+");
		public void createMarkerScript(StringBuilder buff, IBizObj mapPoint)
		{
			string lat = (string)mapPoint.get("location.latitude");
			string lng = (string)mapPoint.get("location.longitude");
			if (!Swaf.Cmn.IsEmpty(lat) && !Swaf.Cmn.IsEmpty(lng))
			{
				string mapType = "null";
				IBizObj parent = mapPoint.get("parent") as IBizObj;
				if (parent != null && !Swaf.Cmn.IsEmpty(parent.get("type.mapImageName")))
					mapType = "GGMapIco." + s_nonWord.Replace(parent.get("type.name").ToString(),"");
				string clickEvt, closeEvt;
				getClientEventsForPushPin(mapPoint, out clickEvt, out closeEvt);
				buff.Append("gmap.addOverlay(createTabbedMarker(me, new google.maps.LatLng(").Append(lat).Append(",").Append(lng).Append("),");
				buff.Append("'").Append(mapPoint.get("location.location").ToString().Replace("'", "\\")).Append("',"); //shoud be summary of article
				buff.Append("'.',").Append(mapType).Append(",'").Append(clickEvt).Append("',");
				buff.Append("function(){").Append(closeEvt).Append("}));"); //should be body of article
			}
		}

		protected void getClientEventsForPushPin(IBizObj mapPoint, out string clickEvt, out string closeEvt)
		{
			FlexiMap m = new FlexiMap();
			if (mapPoint.get("parent") != null)
				m["parentId"] = ((IBizObj)mapPoint.get("parent")).KeyValue;
			m["meta"] = mapPoint.get("meta");
			StringBuilder clickBuff = new StringBuilder(512);
			foreach (PushPin p in PushPins)
				if (p.Meta.CompareTo(mapPoint.get("meta")) == 0 || Swaf.Cmn.IsEmpty(p.Meta))
					clickBuff.Append(Swaf.Application.currentApp.resMgr.resolve(p.OnClick, m));
			StringBuilder closeBuff = new StringBuilder(512);
			foreach (PushPin p in PushPins)
				if (p.Meta.CompareTo(mapPoint.get("meta")) == 0 || Swaf.Cmn.IsEmpty(p.Meta))
					closeBuff.Append(Swaf.Application.currentApp.resMgr.resolve(p.OnClose, m));

			clickEvt = clickBuff.Replace("'", "\\'").ToString();
			closeEvt = closeBuff.ToString();
		}

		public StringBuilder createMapIconsScript(IBizObjList[] mapIcons)
		{
			StringBuilder buff = new StringBuilder(1024);
			buff.Append("var GGMapIco = {};");
			if(mapIcons != null)
				foreach (IBizObjList mapTypes in mapIcons)
					if(mapTypes != null)
						foreach(IBizObj mapType in mapTypes)
							if (!Swaf.Cmn.IsEmpty(mapType.get("mapImageName")))
							{
								buff.Append("var i = new GIcon(G_DEFAULT_ICON);");
								buff.Append("i.image = \"http://").Append(Page.Request.Url.Host);
								if (Page.Request.Url.Port != 80)
									buff.Append(":").Append(Page.Request.Url.Port);
								buff.Append("/img/").Append(mapType.get("cacheName")).Append("/MapPin/").Append(mapType.get("mapImageName")).Append("\";");
								buff.Append("i.iconSize = new GSize(24,37);");
								buff.Append("i.infoWindowAnchor = new GPoint(24,1);");
								buff.Append("i.iconAnchor = new GPoint(12,36);");
								buff.Append("GGMapIco.").Append(s_nonWord.Replace(mapType.get("name").ToString(),"")).AppendLine(" = i;");
							}

			return buff;
		}

		#region IBizObjListDisplay2 Members

		protected string m_dataDetailBizRule = null;
		public string DataDetailBizRule	{get{return (string)getOffline("m_dataDetailBizRule");}	set{putOffline("m_dataDetailBizRule", value);}}

		protected string m_dataSourceBizRule = null;
		public string DataSourceBizRule { get { return (string)getOffline("m_dataSourceBizRule"); } set { putOffline("m_dataSourceBizRule", value); } }

		protected object m_dataSourceBizRuleParam = null;
		public string DataSourceBizRuleParam { get { return (string)getOffline("m_dataSourceBizRuleParam"); } set { putOffline("m_dataSourceBizRuleParam", value); } }
		#endregion

		#region IBizObjListDisplay Members

		public event BizObjChanged BizObjAdded;

		public event BizObjChanged BizObjDeleted;

		public event BizObjSelectedInfo BizObjSelected;

		public event BizObjChanged BizObjUpdated;

		protected bool m_drivenByBizProc = false;
		public bool DrivenByBizProc { get { return (bool)getOffline("m_drivenByBizProc"); } set { putOffline("m_drivenByBizProc", value); } }

		protected Privileges m_editPriv = Privileges.ReadOnly;
		public Privileges EditPrivilege { get { return (Privileges)getOffline("m_editPriv"); } set { putOffline("m_editPriv", value); } }

		protected int m_maxElements = -1;
		protected bool m_maxElIsPercent = false;
		public string MaxElements
		{
			get
			{
				if (m_maxElIsPercent)
					return m_maxElements + "%";
				return m_maxElements.ToString();
			}
			set
			{
				if (value.EndsWith("%"))
				{
					m_maxElIsPercent = true;
					m_maxElements = int.Parse(value.Substring(0, value.Length - 1));
				}
				else
					m_maxElements = int.Parse(value);
			}
		}

		protected int realMaxElements()
		{
			return -1;
		}

		public IBizObj SelectedBizObj
		{
			get
			{
				return null;
			}
			set
			{
			}
		}

		public object SelectedBizObjKeyValue
		{
			get
			{
				return null;
			}
			set
			{
			}
		}

		public void getSelectedBizObjs(IBizObjList selected)
		{
		}

		public void refresh()
		{
		}

		public void setSelectedBizObjs(IBizObjList selected)
		{
		}

		public virtual void showBizObjs(IBusinessProcess bizproc, IBizObjCursor list)
		{
			if(bizproc == null || Page == null)
				return;
			m_bizObjCursor = list;
		}

		protected override void Render(HtmlTextWriter writer)
		{
			clearControls();
			createControls();
			setupMapPointStartupScript();
			base.Render(writer);
		}

		public void updateBizObjs()
		{
		}

		#endregion

	}

	[AspNetHostingPermission(SecurityAction.Demand, Level = AspNetHostingPermissionLevel.Minimal)]
	[PersistenceModeAttribute(PersistenceMode.InnerProperty)]
	[Serializable]
	public class PushPin
	{
		protected string m_meta = "";
		protected string m_click = null, m_close = null;

		public string Meta { get { return m_meta; } set { m_meta = value; } }
		public string OnClick { get { return m_click; } set { m_click = value; } }
		public string OnClose { get { return m_close; } set { m_close = value; } }

	}

}
